home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 112 / EnigmaAmiga112CD.iso / dalla rivista / news / orbit / source / mission.c < prev    next >
C/C++ Source or Header  |  2000-05-01  |  25KB  |  1,187 lines

  1. /*
  2.     Amiga port by Oliver Gantert
  3.  
  4.     27.04.2000 - fixed some compiler warnings
  5. */
  6. /*
  7.  
  8. ORBIT, a freeware space combat simulator
  9. Copyright (C) 1999  Steve Belczyk <steve1@genesis.nred.ma.us>
  10.  
  11. This program is free software; you can redistribute it and/or
  12. modify it under the terms of the GNU General Public License
  13. as published by the Free Software Foundation; either version 2
  14. of the License, or (at your option) any later version.
  15.  
  16. This program is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. GNU General Public License for more details.
  20.  
  21. You should have received a copy of the GNU General Public License
  22. along with this program; if not, write to the Free Software
  23. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  24.  
  25. */
  26.  
  27. #include "orbit.h"
  28.  
  29. /* File descriptor stack */
  30. #define NFDS (16)
  31. FILE *fd[NFDS];
  32. int sp;
  33.  
  34. char token[128], tokens[10][128];
  35. int iact;
  36. int planet_index;
  37. int weapon_index;
  38.  
  39. int TAflag;
  40. #define TRIGGER 0
  41. #define ACTION 1
  42.  
  43. void ReadMission (char *msn)
  44. /*
  45.  *  Read a mission file
  46.  */
  47. {
  48.   char fn[128], buf[128];
  49.   int i;
  50.  
  51.   /* Bye if no file name */
  52.   if ( (msn == NULL) || (msn[0] == 0) )
  53.   {
  54.     Mprint ("No mission to load!");
  55.     Log ("ReadMission: No mission to load!");
  56.     return;
  57.   }
  58.  
  59.   /* Construct file name */
  60.   sprintf (fn, "missions/%s", msn);
  61.  
  62.   Log ("ReadMission: reading %s", fn);
  63.  
  64.   /* Init some stuff */
  65.   mission.cursor[0] = mission.cursor[1] = mission.cursor[2] = 0.0;
  66.   mission.verbose = 0;
  67.   strcpy (mission.fn, msn);
  68.   player.score = 0;
  69.   mission.briefing[0] = 0;
  70.   for (i=0; i<10; i++) tokens[i][0] = 0;
  71.   sp = 0;
  72.  
  73.   /* Reset targets, events, weapons and planets, etc; */
  74.   InitTargets();
  75.   ResetEvents();
  76.   InitWeapons();
  77.   ResetPlanets();
  78.   InitWaypoints();
  79.   lock.target = (-1);
  80.  
  81.   /* Open the file */
  82.   if (NULL == (fd[0] = fopen (fn, "r")))
  83.   {
  84.     Log ("ReadMission: Can't open %s", fn);
  85.     sprintf (buf, "Can't open mission file %s", fn);
  86.     Mprint (buf);
  87.     return;
  88.   }
  89.  
  90.   /* Process tokens */
  91.   while (GetToken())
  92.   {
  93.     if (!strcasecmp (token, "cursor")) Cursor();
  94.     else if (!strcasecmp (token, "player")) Player();
  95.     else if (!strcasecmp (token, "waypoint")) Waypoint();
  96.     else if (!strcasecmp (token, "object")) Object();
  97.     else if (!strcasecmp (token, "briefing")) Briefing();
  98.     else if (!strcasecmp (token, "verbose")) mission.verbose = 1;
  99.     else if (!strcasecmp (token, "terse")) mission.verbose = 0;
  100.     else if (!strcasecmp (token, "event")) Event();
  101.     else if (!strcasecmp (token, "planet")) Planet();
  102.     else if (!strcasecmp (token, "weapon")) Weapon();
  103.     else if (!strcasecmp (token, "include")) Include();
  104.     else UnrecognizedToken();
  105.   }
  106.  
  107.   /* Add mission to saved games list */
  108.   AddSave (mission.fn);
  109.  
  110.   /* Show mission briefing */
  111.   Mprint (mission.briefing); 
  112.   
  113.   Log ("ReadMission: Done reading mission");
  114. }
  115.  
  116. int GetToken()
  117. /*
  118.  *  Read next token from file
  119.  */
  120. {
  121.   /* Get next token */
  122.   if (1 != fscanf (fd[0], "%s", token))
  123.   {
  124.     fclose (fd[0]);
  125.  
  126.     /* Inside include? */
  127.     if (!PopFD()) return 0;
  128.  
  129.     /* Recurse */
  130.     return (GetToken());
  131.   }
  132.  
  133.   RotateTokens();
  134.  
  135.   /* Start of comment? */
  136.   if (strcasecmp (token, "/*")) return (1);
  137.  
  138.   /* Look for end of comment */
  139.   do
  140.   {
  141.     if (1 != fscanf (fd[0], "%s", token))
  142.     {
  143.       fclose (fd[0]);
  144.  
  145.       /* Inside include? */
  146.       if (!PopFD()) return 0;
  147.     }
  148.     RotateTokens();
  149.   }
  150.   while (strcasecmp (token, "*/"));
  151.  
  152.   /* Recurse to get next token */
  153.   return (GetToken());  
  154. }
  155.  
  156. void RotateTokens()
  157. {
  158.   int i;
  159.  
  160.   for (i=9; i>0; i--) strcpy (tokens[i], tokens[i-1]);
  161.   strcpy (tokens[0], token);
  162. }
  163.  
  164. void ShowTokens()
  165. {
  166.   Log ("Recent tokens: %s %s %s %s %s %s %s %s %s %s",
  167.   tokens[9], tokens[8], tokens[7], tokens[6], tokens[5],
  168.   tokens[4], tokens[3], tokens[2], tokens[1], tokens[0]);
  169. }
  170.  
  171. int GetBrace()
  172. /*
  173.  *  Get open brace, error otherwise
  174.  */
  175. {
  176.   if (!GetToken())
  177.   {
  178.     Log ("GetBrace: Unexpected end of file in %s!", mission.fn);
  179.     ShowTokens();
  180.     FinishSound();
  181.     CloseLog();
  182.     exit (0);
  183.   }
  184.  
  185.   if (strcmp (token, "{"))
  186.   {
  187.     Log ("GetBrace: Expected '{', found '%s'", token);
  188.     ShowTokens();
  189.     FinishSound();
  190.     CloseLog();
  191.     exit (0);
  192.   }
  193.  
  194.   return (1);
  195. }
  196.  
  197. int GetRequiredToken()
  198. /*
  199.  *  Get a token, error if EOF
  200.  */
  201. {
  202.   if (!GetToken())
  203.   {
  204.     Log ("GetRequiredToken: Unexpected end of file in %s!", mission.fn);
  205.     ShowTokens();
  206.     FinishSound();
  207.     CloseLog();
  208.     exit (0);
  209.   }
  210.   return(1);
  211. }
  212.  
  213. void Cursor()
  214. {
  215.   int xyzflag, relflag;
  216.   double x;
  217.  
  218.   GetBrace();
  219.  
  220.   xyzflag = 0;
  221.  
  222.   while (GetToken())
  223.   {
  224.     if (!strcmp (token, "}")) return;
  225.  
  226.     if ( (token[0] == '+') || (token[0] == '-') ||
  227.     ((token[0] >= '0') && (token[0] <= '9')) )
  228.     {
  229.       /* It's a number */
  230.  
  231.       /* See if abs or relative */
  232.       relflag = 0;
  233.       if (token[0] == '+') relflag = 1;
  234.       if (token[0] == '-') relflag = 1;
  235.  
  236.       sscanf (token, "%lf", &x);
  237.       x = x / KM_TO_UNITS1;
  238.  
  239.       if (relflag)
  240.       mission.cursor[xyzflag] += x;
  241.       else
  242.       mission.cursor[xyzflag] = x;
  243.  
  244.       xyzflag = (xyzflag + 1) % 3;
  245.  
  246.       if (mission.verbose)
  247.       Log ("Set cursor to %lf %lf %lf",
  248.       mission.cursor[0],
  249.       mission.cursor[1],
  250.       mission.cursor[2]);
  251.     }
  252.     else
  253.     {
  254.       /* It's a planet */
  255.       if (!CursorPlanet()) CursorObject();
  256.  
  257.       if (mission.verbose)
  258.       {
  259.         Log ("Cursor: Setting cursor to %s",
  260.         token);
  261.         Log ("Cursor: (Set cursor to %lf %lf %lf)",
  262.         mission.cursor[0],
  263.         mission.cursor[1],
  264.         mission.cursor[2]);
  265.       }
  266.     }
  267.   }
  268. }
  269.  
  270. int CursorPlanet()
  271. {
  272.   int p;
  273.  
  274.   for (p=0; p<NPLANETS; p++)
  275.   {
  276.     if (!strcasecmp (token, planet[p].name))
  277.     {
  278.       Vset (mission.cursor, planet[p].pos);
  279.       return 1;
  280.     }
  281.   }
  282.  
  283.   Log ("CursorPlanet: No such planet: %s", token);
  284.   return 0;
  285. }
  286.  
  287. int CursorObject()
  288. {
  289.   int t;
  290.  
  291.   for (t=0; t<NTARGETS; t++)
  292.   {
  293.     if (target[t].age > 0.0)
  294.     {
  295.       if (!strcasecmp (token, target[t].name))
  296.       {
  297.         Vset (mission.cursor, target[t].pos);
  298.         return 1;
  299.       }
  300.     }
  301.   }
  302.  
  303.   Log ("CursorObject: No such object: %s", token);
  304.   return 0;
  305. }
  306.  
  307. void Player()
  308. {
  309.   GetBrace();
  310.  
  311.   mission.player[0] = mission.cursor[0];
  312.   mission.player[1] = mission.cursor[1];
  313.   mission.player[2] = mission.cursor[2];
  314.  
  315.   player.vel[0] = player.vel[1] = player.vel[2] = 0.0;
  316.  
  317.   if (mission.verbose)
  318.   Log ("Player: Set player position to %lf %lf %lf",
  319.   mission.player[0], mission.player[1], mission.player[2]);
  320.  
  321.   Vset (player.pos, mission.player);
  322.  
  323.   while (GetToken())
  324.   {
  325.     if (!strcmp (token, "}")) return;
  326.     else
  327.     {
  328.       UnrecognizedToken();
  329.     }
  330.   }
  331. }
  332.  
  333. void Waypoint()
  334. {
  335.   GetBrace();
  336.  
  337.   if (mission.verbose) Log ("Waypoint: Adding waypoint %d", nwaypoints);
  338.   AddWaypoint (mission.cursor);
  339.  
  340.   while (GetToken())
  341.   {
  342.     if (!strcmp (token, "}")) return;
  343.     else
  344.     {
  345.       UnrecognizedToken();
  346.     }
  347.   }
  348. }
  349.  
  350. void Briefing()
  351. {
  352.   mission.briefing[0] = 0;
  353.  
  354.   GetBrace();
  355.  
  356.   while (GetToken())
  357.   {
  358.     if (!strcmp (token, "}"))
  359.     {
  360.       if (mission.verbose)
  361.       Log ("Briefing: %s", mission.briefing);
  362.       return;
  363.     }
  364.     strcat (mission.briefing, " ");
  365.     strcat (mission.briefing, token);
  366.   }
  367. }
  368.  
  369. void UnrecognizedToken()
  370. {
  371.   Log ("UnrecognizedToken: Skipping unrecognized token \"%s\" in %s",
  372.   token, mission.fn);
  373.   ShowTokens();
  374. }
  375.  
  376. void Object()
  377. {
  378.   int t;
  379.  
  380.   GetBrace();
  381.  
  382.   /* Find an unused target */
  383.   t = FindTarget();
  384.  
  385.   if (mission.verbose) Log ("Object: Creating object %d", t);
  386.  
  387.   /* Set it up */
  388.   Vset (target[t].pos, mission.cursor);
  389.   target[t].age = 0.1;
  390.   target[t].view[0] = 1.0;
  391.   target[t].view[1] = target[t].view[2] = 0.0;
  392.  
  393.   target[t].hidden = 0;
  394.   target[t].invisible = 0;
  395.  
  396.   target[t].up[0] = 0.0;
  397.   target[t].up[1] = 0.0;
  398.   target[t].up[2] = 1.0;
  399.  
  400.   target[t].strategy = STRAT_DONOTHING;
  401.   target[t].friendly = 0;
  402.   target[t].weapon = NPLAYER_WEAPONS;
  403.  
  404.   Crossp (target[t].right, target[t].up, target[t].view);
  405.  
  406.   target[t].vel[0] = target[t].vel[1] = target[t].vel[2] = 0.0;
  407.  
  408.   target[t].move_forward = target[t].move_backward =
  409.   target[t].move_up = target[t].move_down =
  410.   target[t].move_pitchleft = target[t].move_pitchright =
  411.   target[t].move_left = target[t].move_right = 0.0;
  412.  
  413.   target[t].model = 0;
  414.   target[t].list = model[0].list;
  415.   target[t].score = 0;
  416.   strcpy (target[t].name, model[0].name);
  417.  
  418.   target[t].maxshields = 100.0;
  419.   target[t].shieldregen = SHIELD_REGEN;
  420.   target[t].turnrate = 0.3;
  421.   target[t].maxvel = 0.01;
  422.  
  423.   while (GetToken())
  424.   {
  425.     if (!strcmp (token, "}")) return;
  426.  
  427.     if (!strcasecmp (token, "model")) ObjModel (t);
  428.     else if (!strcasecmp (token, "score")) ObjScore (t);
  429.     else if (!strcasecmp (token, "strategy")) ObjStrategy (t);
  430.     else if (!strcasecmp (token, "name")) ObjName (t);
  431.     else if (!strcasecmp (token, "hidden")) ObjHidden (t);
  432.     else if (!strcasecmp (token, "weapon")) ObjWeapon (t);
  433.     else if (!strcasecmp (token, "friendly")) ObjFriendly (t);
  434.     else if (!strcasecmp (token, "maxshields")) ObjMaxshields (t);
  435.     else if (!strcasecmp (token, "shieldregen")) ObjShieldregen (t);
  436.     else if (!strcasecmp (token, "turnrate")) ObjTurnrate (t);
  437.     else if (!strcasecmp (token, "speed")) ObjSpeed (t);
  438.     else if (!strcasecmp (token, "invisible")) ObjInvisible (t);
  439.     else UnrecognizedToken ();
  440.   }
  441. }
  442.  
  443. void ObjMaxshields (int t)
  444. {
  445.   GetRequiredToken();
  446.   target[t].maxshields = atof (token);
  447.   target[t].shields = target[t].maxshields;
  448.  
  449.   if (mission.verbose)
  450.   Log ("ObjMaxshields: Object %d shields set to %lf", t, target[t].shields);
  451. }
  452.  
  453. void ObjShieldregen (int t)
  454. {
  455.   GetRequiredToken();
  456.   target[t].shieldregen = atof (token);
  457.  
  458.   if (mission.verbose)
  459.   Log ("ObjShieldregen: Object %d regen set to %lf", t, target[t].shieldregen);
  460. }
  461.  
  462. void ObjTurnrate (int t)
  463. {
  464.   GetRequiredToken();
  465.   target[t].turnrate = atof (token);
  466.  
  467.   if (mission.verbose)
  468.   Log ("ObjTurnrate: Object %d turnrate set to %lf", t, target[t].turnrate);
  469. }
  470.  
  471. void ObjSpeed (int t)
  472. {
  473.   GetRequiredToken();
  474.   target[t].maxvel = atof (token);
  475.  
  476.   if (mission.verbose)
  477.   Log ("ObjSpeed: Object %d speed set to %lf", t, target[t].maxvel);
  478. }
  479.  
  480. void ObjModel (int t)
  481. {
  482.   int m;
  483.  
  484.   GetRequiredToken();
  485.  
  486.   m = LoadModel (token);
  487.   target[t].model = m;
  488.   if (m == (-1))
  489.   {
  490.     Log ("ObjModel: Couldn't open model %s", token);
  491.   }
  492.   else
  493.   {
  494.     target[t].list = model[m].list;
  495.   }
  496.  
  497.   if (mission.verbose)
  498.   Log ("ObjModel: Object %d model set to %s", t, model[m].name);
  499. }
  500.  
  501. void ObjScore (int t)
  502. {
  503.   GetRequiredToken();
  504.  
  505.   sscanf (token, "%d", &target[t].score);
  506.  
  507.   if (mission.verbose) Log ("ObjScore: Object %d score is %d",
  508.   t, target[t].score);
  509. }
  510.  
  511. void ObjName (int t)
  512. {
  513.   GetRequiredToken();
  514.  
  515.   strcpy (target[t].name, token);
  516.  
  517.   if (mission.verbose) Log ("ObjName: Object %d named \"%s\"",
  518.   t, target[t].name);
  519. }
  520.  
  521. void ObjStrategy (int t)
  522. {
  523.   GetRequiredToken();
  524.  
  525.   if (mission.verbose)
  526.   Log ("ObjStrategy: Setting object %d strategy to %s", t, token);
  527.  
  528.   if (!strcasecmp (token, "sit1"))
  529.   {
  530.     target[t].strategy = STRAT_SIT1;
  531.   }
  532.   else if (!strcasecmp (token, "sit2"))
  533.   {
  534.     target[t].strategy = STRAT_SIT2;
  535.   }
  536.   else if (!strcasecmp (token, "sit3"))
  537.   {
  538.     target[t].strategy = STRAT_SIT3;
  539.   }
  540.   else if (!strcasecmp (token, "sit4"))
  541.   {
  542.     target[t].strategy = STRAT_SIT4;
  543.   }
  544.   else if (!strcasecmp (token, "hunt1"))
  545.   {
  546.     target[t].strategy = STRAT_HUNT1;
  547.   }
  548.   else if (!strcasecmp (token, "hunt2"))
  549.   {
  550.     target[t].strategy = STRAT_HUNT2;
  551.   }
  552.   else if (!strcasecmp (token, "hunt3"))
  553.   {
  554.     target[t].strategy = STRAT_HUNT3;
  555.   }
  556.   else if (!strcasecmp (token, "hunt4"))
  557.   {
  558.     target[t].strategy = STRAT_HUNT4;
  559.   }
  560.   else if (!strcasecmp (token, "donothing"))
  561.   {
  562.     target[t].strategy = STRAT_DONOTHING;
  563.   }
  564.   else
  565.   {
  566.     Log ("ObjStrategy: No such strategy: %s", token);
  567.   }
  568. }
  569.  
  570. void ObjHidden (int t)
  571. {
  572.   target[t].hidden = 1;
  573.  
  574.   if (mission.verbose)
  575.   Log ("ObjHidden: Object %d is hidden", t);
  576. }
  577.  
  578. void ObjInvisible (int t)
  579. {
  580.   target[t].invisible = 1;
  581.  
  582.   if (mission.verbose)
  583.   Log ("ObjInvisible: Object %d is invisible", t);
  584. }
  585.  
  586. void ObjFriendly (int t)
  587. {
  588.   target[t].friendly = 1;
  589.  
  590.   if (mission.verbose)
  591.   Log ("ObjFriendly: Object %d is friendly", t);
  592. }
  593.  
  594. void ObjWeapon (int t)
  595. {
  596.   GetRequiredToken();
  597.   target[t].weapon = atoi (token);
  598.   if ( (target[t].weapon >= NWEAPONS) ||
  599.   (target[t].weapon < 0) )
  600.   target[t].weapon = 0;
  601.  
  602.   if (mission.verbose)
  603.   Log ("ObjWeapon: Object %d weapon set to %d", t, target[t].weapon);
  604. }
  605.  
  606. void Event()
  607. {
  608.   int e, a;
  609.  
  610.   GetBrace();
  611.  
  612.   /* Find an unused event entry */
  613.   e = FindEvent();
  614.  
  615.   if (mission.verbose) Log ("Event: Creating event %d", e);
  616.  
  617.   /* Index to next action */
  618.   iact = (-1);
  619.  
  620.   /* Values for triggers or actions? */
  621.   TAflag = TRIGGER;
  622.  
  623.   /* Set up some stuff */
  624.   event[e].name[0] = 0;
  625.   event[e].enabled = 1;
  626.   event[e].trigger = EVENT_NULL;
  627.   Vset (event[e].pos, mission.cursor);
  628.   event[e].ivalue = 0;
  629.   event[e].fvalue = 0.0;
  630.   for (a=0; a<ACTIONS_PER_EVENT; a++)
  631.   {
  632.     event[e].action[a].active = 0;
  633.     event[e].action[a].action = EVENT_NULL;
  634.     event[e].action[a].ivalue = 0;
  635.     event[e].action[a].fvalue = 0.0;
  636.   }
  637.  
  638.   /* Process rest of event tokens */
  639.   while (1)
  640.   {
  641.     GetRequiredToken();
  642.     if (!strcmp (token, "}"))
  643.     {
  644.       /* Convert units if this is Approach or Depart */
  645.       if ( (event[e].trigger == EVENT_APPROACH) ||
  646.       (event[e].trigger == EVENT_STOPNEAR) ||
  647.       (event[e].trigger == EVENT_DEPART) )
  648.       {
  649.         event[e].fvalue /= KM_TO_UNITS1;
  650.       }
  651.  
  652.       /* Shields is weird, has a text and floating value */
  653.       if (event[e].trigger == EVENT_SHIELDS)
  654.       {
  655.         sscanf (event[e].cvalue, "%*s %lf", &event[e].fvalue);
  656.         sscanf (event[e].cvalue, "%s", event[e].cvalue);
  657.         if (mission.verbose)
  658.         Log ("Event: EVENT_SHIELDS target %s value %lf",
  659.         event[e].cvalue, event[e].fvalue);
  660.       }
  661.  
  662.       return;
  663.     }
  664.  
  665.     if (!strcasecmp (token, "trigger")) EvTrigger (e);
  666.     else if (!strcasecmp (token, "name")) EvName (e);
  667.     else if (!strcasecmp (token, "action")) EvAction (e);
  668.     else if (!strcasecmp (token, "value")) EvValue (e);
  669.     else if (!strcasecmp (token, "enabled")) event[e].enabled = 1;
  670.     else if (!strcasecmp (token, "disabled")) event[e].enabled = 0;
  671.     else UnrecognizedToken ();
  672.   }
  673. }
  674.  
  675. void EvName (int e)
  676. {
  677.   GetRequiredToken();
  678.   strcpy (event[e].name, token);
  679.  
  680.   if (mission.verbose)
  681.   Log ("EvName: Event %d named %s", e, token);
  682. }
  683.  
  684. void EvTrigger (int e)
  685. {
  686.   GetRequiredToken();
  687.  
  688.   TAflag = TRIGGER;
  689.  
  690.   if (mission.verbose)
  691.   Log ("EvTrigger: Setting event %d trigger to %s", e, token);
  692.  
  693.   if (!strcasecmp (token, "approach")) event[e].trigger = EVENT_APPROACH;
  694.   else if (!strcasecmp (token, "depart")) event[e].trigger = EVENT_DEPART;
  695.   else if (!strcasecmp (token, "true")) event[e].trigger = EVENT_TRUE;
  696.   else if (!strcasecmp (token, "score")) event[e].trigger = EVENT_SCORE;
  697.   else if (!strcasecmp (token, "destroy")) event[e].trigger = EVENT_DESTROY;
  698.   else if (!strcasecmp (token, "alarm")) event[e].trigger = EVENT_ALARM;
  699.   else if (!strcasecmp (token, "stopnear")) event[e].trigger = EVENT_STOPNEAR;
  700.   else if (!strcasecmp (token, "shields")) event[e].trigger = EVENT_SHIELDS;
  701.   else UnrecognizedToken();
  702. }
  703.  
  704. void EvAction (int e)
  705. {
  706.   /* Bump action index */
  707.   iact++;
  708.   if (iact >= ACTIONS_PER_EVENT)
  709.   {
  710.     Log ("EvAction: Too many actions in event %d!", e);
  711.     iact--;
  712.   }
  713.  
  714.   event[e].action[iact].active = 1;
  715.  
  716.   TAflag = ACTION;
  717.  
  718.   GetRequiredToken();
  719.  
  720.   if (mission.verbose)
  721.   Log ("EvAction: Setting event %d.%d action to %s", e, iact, token);
  722.  
  723.   if (!strcasecmp (token, "message")) event[e].action[iact].action = EVENT_MESSAGE;
  724.   else if (!strcasecmp (token, "hide")) event[e].action[iact].action = EVENT_HIDE;
  725.   else if (!strcasecmp (token, "unhide")) event[e].action[iact].action = EVENT_UNHIDE;
  726.   else if (!strcasecmp (token, "destroy")) event[e].action[iact].action = EVENT_DESTROY;
  727.   else if (!strcasecmp (token, "score")) event[e].action[iact].action = EVENT_SCORE;
  728.   else if (!strcasecmp (token, "enable")) event[e].action[iact].action = EVENT_ENABLE;
  729.   else if (!strcasecmp (token, "disable")) event[e].action[iact].action = EVENT_DISABLE;
  730.   else if (!strcasecmp (token, "loadmission")) event[e].action[iact].action = EVENT_LOADMISSION;
  731.   else if (!strcasecmp (token, "stop")) event[e].action[iact].action = EVENT_STOP;
  732.   else if (!strcasecmp (token, "boom")) event[e].action[iact].action = EVENT_BOOM;
  733.   else if (!strcasecmp (token, "flash")) event[e].action[iact].action = EVENT_FLASH;
  734.   else if (!strcasecmp (token, "moveobject")) event[e].action[iact].action = EVENT_MOVEOBJECT;
  735.   else if (!strcasecmp (token, "moveplayer")) event[e].action[iact].action = EVENT_MOVEPLAYER;
  736.   else if (!strcasecmp (token, "moveplanet")) event[e].action[iact].action = EVENT_MOVEPLANET;
  737.   else if (!strcasecmp (token, "hideplanet")) event[e].action[iact].action = EVENT_HIDEPLANET;
  738.   else if (!strcasecmp (token, "unhideplanet")) event[e].action[iact].action = EVENT_UNHIDEPLANET;
  739.   else if (!strcasecmp (token, "betray")) event[e].action[iact].action = EVENT_BETRAY;
  740.   else UnrecognizedToken();
  741. }
  742.  
  743. void EvValue (int e)
  744. {
  745.   char buf[4096];
  746.  
  747.   GetRequiredToken();
  748.  
  749.   buf[0] = 0;
  750.  
  751.   if (strcmp (token, "{"))
  752.   {
  753.     strcpy (buf, token);
  754.   }
  755.   else
  756.   {
  757.     /* Allow text enclosed in braces */
  758.     while (1)
  759.     {
  760.       GetRequiredToken();
  761.       if (!strcmp (token, "}"))
  762.       {
  763.         break;
  764.       }
  765.  
  766.       /* Add space if not first one */
  767.       if (0 != buf) strcat (buf, " ");
  768.       strcat (buf, token);
  769.     }
  770.   }
  771.   
  772.   /* Figure out what to do with this value */
  773.   if (TAflag == TRIGGER)
  774.   {
  775.     /* It's the trigger's value */
  776.     if (NULL == (event[e].cvalue = (char *) malloc (1+strlen(buf))))
  777.     {
  778.       OutOfMemory();
  779.     }
  780.     strcpy (event[e].cvalue, buf);
  781.     event[e].ivalue = atoi (buf);
  782.     event[e].fvalue = atof (buf);
  783.  
  784.     if (mission.verbose)
  785.     Log ("EvValue: Event %d trigger value set to %s", e, buf);
  786.   }
  787.   else
  788.   {
  789.     /* It's the action's value */
  790.     if (NULL == (event[e].action[iact].cvalue = (char *) malloc (1+strlen(buf))))
  791.     {
  792.       OutOfMemory();
  793.     }
  794.     strcpy (event[e].action[iact].cvalue, buf);
  795.     event[e].action[iact].ivalue = atoi (buf);
  796.     event[e].action[iact].fvalue = atof (buf);
  797.  
  798.     if (mission.verbose)
  799.     Log ("EvValue: Event %d.%d action set to %s", e, iact, buf);
  800.   }
  801. }
  802.  
  803. void Weapon()
  804. /*
  805.  *  Handle weapon token
  806.  */
  807. {
  808.   weapon_index = (-1);
  809.  
  810.   GetBrace();
  811.  
  812.   while (GetToken())
  813.   {
  814.     if (!strcmp (token, "}"))
  815.     {
  816.       /* Recompute weapon ranges */
  817.       WeaponRanges();
  818.       return;
  819.     }
  820.  
  821.     if (!strcasecmp (token, "index")) WeaponIndex();
  822.     else if (!strcasecmp (token, "name")) WeaponName();
  823.     else if (!strcasecmp (token, "speed")) WeaponSpeed();
  824.     else if (!strcasecmp (token, "yield")) WeaponYield();
  825.     else if (!strcasecmp (token, "idle")) WeaponIdle();
  826.     else if (!strcasecmp (token, "expire")) WeaponExpire();
  827.     else if (!strcasecmp (token, "renderer")) WeaponRenderer();
  828.     else if (!strcasecmp (token, "color")) WeaponColor();
  829.     else UnrecognizedToken();
  830.   }
  831. }
  832.  
  833. void WeaponIndex()
  834. {
  835.   int w;
  836.  
  837.   GetToken();
  838.  
  839.   w = atoi (token);
  840.   if ( (w >= 0) && (w < NWEAPONS) )
  841.   {
  842.     weapon_index = w;
  843.  
  844.     if (mission.verbose)
  845.     Log ("WeaponIndex: Index set to %d", w);
  846.   }
  847. }
  848.  
  849. void WeaponName()
  850. {
  851.   GetToken();
  852.  
  853.   if (weapon_index == (-1)) return;
  854.   strcpy (weapon[weapon_index].name, token);
  855.  
  856.   if (mission.verbose)
  857.   Log ("WeaponName: Weapon %d named %s", weapon_index, token);
  858. }
  859.  
  860. void WeaponSpeed()
  861. {
  862.   GetToken();
  863.  
  864.   if (weapon_index == (-1)) return;
  865.   weapon[weapon_index].speed = atof (token) / KM_TO_UNITS1;
  866.  
  867.   if (mission.verbose)
  868.   Log ("WeaponSpeed: Weapon %d speed is %lf", weapon_index, weapon[weapon_index].speed);
  869. }
  870.  
  871. void WeaponYield()
  872. {
  873.   GetToken();
  874.  
  875.   if (weapon_index == (-1)) return;
  876.   weapon[weapon_index].yield = atof (token);
  877.  
  878.   if (mission.verbose)
  879.   Log ("WeaponYield: Weapon %d yield is %lf", weapon_index, weapon[weapon_index].yield);
  880. }
  881.  
  882. void WeaponIdle()
  883. {
  884.   GetToken();
  885.  
  886.   if (weapon_index == (-1)) return;
  887.   weapon[weapon_index].idle = atof (token);
  888.  
  889.   if (mission.verbose)
  890.   Log ("WeaponIdle: Weapon %d idle is %lf", weapon_index, weapon[weapon_index].idle);
  891. }
  892.  
  893. void WeaponExpire()
  894. {
  895.   GetToken();
  896.  
  897.   if (weapon_index == (-1)) return;
  898.   weapon[weapon_index].expire = atof (token);
  899.  
  900.   if (mission.verbose)
  901.   Log ("WeaponExpire: Weapon %d expire is %lf", weapon_index, weapon[weapon_index].expire);
  902. }
  903.  
  904. void WeaponRenderer()
  905. {
  906.   int r;
  907.  
  908.   GetToken();
  909.  
  910.   if (weapon_index == (-1)) return;
  911.  
  912.   r = atoi (token);
  913.   if ( (r >= 0) && (r < 5) )
  914.   {
  915.     weapon[weapon_index].renderer = r;
  916.  
  917.     if (mission.verbose)
  918.     Log ("WeaponRenderer: Weapon %d renderer set to %d", weapon_index, r);
  919.   }
  920.   else
  921.   {
  922.     Log ("WeaponRenderer: Renderer out of range: %d", r);
  923.   }
  924. }
  925.  
  926. void WeaponColor()
  927. {
  928.   int c, r, g, b;
  929.  
  930.   GetToken();
  931.  
  932.   if (weapon_index == (-1)) return;
  933.  
  934.   sscanf (token, "%i", &c);
  935.  
  936.   r = (0xff0000 & c) >> 16;
  937.   g = (0x00ff00 & c) >> 8;
  938.   b = (0x0000ff & c);
  939.   weapon[weapon_index].color[0] = ((float) r) / 256.0;
  940.   weapon[weapon_index].color[1] = ((float) g) / 256.0;
  941.   weapon[weapon_index].color[2] = ((float) b) / 256.0;
  942. }
  943.  
  944. void Planet()
  945. /*
  946.  *  Handle the planet token
  947.  */
  948. {
  949.   planet_index = (-1);
  950.  
  951.   GetBrace();
  952.  
  953.   while (GetToken())
  954.   {
  955.     if (!strcmp (token, "}")) return;
  956.  
  957.     if (!strcasecmp (token, "name")) PlanetName();
  958.     else if (!strcasecmp (token, "newname")) PlanetNewname();
  959.     else if (!strcasecmp (token, "reposition")) PlanetReposition();
  960.     else if (!strcasecmp (token, "hidden")) PlanetHidden();
  961.     else if (!strcasecmp (token, "map")) PlanetMap();
  962.     else if (!strcasecmp (token, "oblicity")) PlanetOblicity();
  963.     else if (!strcasecmp (token, "radius")) PlanetRadius();
  964.     else UnrecognizedToken();
  965.   }
  966. }
  967.  
  968. void PlanetOblicity()
  969. {
  970.   GetToken();
  971.   if (planet_index == (-1)) return;
  972.  
  973.   planet[planet_index].oblicity = atof (token);
  974.  
  975.   if (mission.verbose)
  976.   Log ("PlanetOblicity: %s oblicity is %lf",
  977.   planet[planet_index].name, planet[planet_index].oblicity);
  978. }
  979.  
  980. void PlanetRadius()
  981. {
  982.   int p;
  983.  
  984.   GetToken();
  985.   if (planet_index == (-1)) return;
  986.  
  987.   p = planet_index;
  988.  
  989.   planet[p].radius = atof (token) / KM_TO_UNITS1;
  990.   planet[p].radius2 = planet[p].radius * planet[p].radius;
  991.   planet[p].mass = planet[p].radius * planet[p].radius2;
  992.   MakePlanetList (p);
  993.  
  994.   if (mission.verbose)
  995.   Log ("PlanetRadius: %s radius is %lf",
  996.   planet[planet_index].name, planet[planet_index].radius);
  997. }
  998.  
  999. void PlanetMap()
  1000. {
  1001.   GetToken();
  1002.   if (planet_index == (-1)) return;
  1003.  
  1004.   /* Set new texture */
  1005.   strcpy (planet[planet_index].texfname, token);
  1006.   planet[planet_index].custom = 1;
  1007.  
  1008.   /* Define new texture */
  1009.   ReadPlanetTexture (planet_index);
  1010.  
  1011.   if (mission.verbose)
  1012.   Log ("PlanetMap: %s texture map is %s",
  1013.   planet[planet_index].name, planet[planet_index].texfname);
  1014. }
  1015.  
  1016. void PlanetHidden()
  1017. {
  1018.   if (planet_index == (-1)) return;
  1019.   planet[planet_index].hidden = 1;
  1020.  
  1021.   if (mission.verbose)
  1022.   Log ("PlanetHidden: %s is hidden", planet[planet_index].name);
  1023. }
  1024.  
  1025. void PlanetReposition()
  1026. {
  1027.   if (planet_index == (-1)) return;
  1028.   Vset (planet[planet_index].pos, mission.cursor);
  1029.  
  1030.   if (mission.verbose)
  1031.   Log ("PlanetReposition: %s new position is (%lf,%lf,%lf)",
  1032.   planet[planet_index].name,
  1033.   mission.cursor[0], mission.cursor[1], mission.cursor[2]);
  1034. }
  1035.  
  1036. void PlanetName()
  1037. {
  1038.   int p;
  1039.  
  1040.   GetToken();
  1041.  
  1042.   if ((-1) == (p = FindPlanetByName(token)))
  1043.   {
  1044.     Log ("PlanetName: No such planet: %s", token);
  1045.     return;
  1046.   }
  1047.  
  1048.   planet_index = p;
  1049.  
  1050.   if (mission.verbose)
  1051.   Log ("PlanetName: Modifying planet %s (index %d)", token, p);
  1052. }
  1053.  
  1054. void PlanetNewname()
  1055. {
  1056.   GetToken();
  1057.   if (planet_index == (-1)) return;
  1058.  
  1059.   strcpy (planet[planet_index].name, token);
  1060.  
  1061.   if (mission.verbose)
  1062.   Log ("PlanetNewname: Planet %d renamed to %s", planet_index, token);
  1063. }
  1064.  
  1065. void Include()
  1066. /*
  1067.  *  Open a new include file
  1068.  */
  1069. {
  1070.   char fn[128];
  1071.  
  1072.   GetRequiredToken();
  1073.  
  1074.   Log ("Include: Including file %s", token);
  1075.  
  1076.   /* Construct file name */
  1077.   sprintf (fn, "missions/%s", token);
  1078.  
  1079.   if (!PushFD())
  1080.   {
  1081.     Log ("Include: Can't include file %s", fn);
  1082.     return;
  1083.   }
  1084.  
  1085.   if (NULL == (fd[0] = fopen (fn, "rt")))
  1086.   {
  1087.     Log ("Include: Can't open include file %s", fn);
  1088.     PopFD();
  1089.     return;
  1090.   }
  1091. }
  1092.  
  1093. int PushFD()
  1094. /*
  1095.  *  Push a file descriptor onto the stack
  1096.  */
  1097. {
  1098.   int i;
  1099.  
  1100.   sp++;
  1101.  
  1102.   /* Overflow? */
  1103.   if (sp >= NFDS)
  1104.   {
  1105.     sp--;
  1106.     Log ("PushFD: Include files nested too deeply");
  1107.     return 0;
  1108.   }
  1109.  
  1110.   /* Push stack */
  1111.   for (i=sp; i>0; i--) fd[i] = fd[i-1];
  1112.  
  1113.   return 1;
  1114. }
  1115.  
  1116. int PopFD()
  1117. /*
  1118.  *  Pop and FD off the stack
  1119.  */
  1120. {
  1121.   int i;
  1122.  
  1123.   if (sp == 0) return 0;
  1124.  
  1125.   sp--;
  1126.   for (i=0; i<=sp; i++) fd[i] = fd[i+1];
  1127.  
  1128.   return 1;
  1129. }
  1130.  
  1131. #ifdef AMIGA
  1132. int strcasecmp (s1, s2) 
  1133. char *s1, *s2; 
  1134. {
  1135.   int l1, l2, i; 
  1136.   char c1, c2; 
  1137.   
  1138.   l1 = strlen (s1); 
  1139.   l2 = strlen (s2); 
  1140.   
  1141.   if (l1 != l2) return (1); 
  1142.   if (l1 == 0) return (0); 
  1143.   
  1144.   for (i=0; i<l1; i++) 
  1145.   {
  1146.     c1 = tolower (s1[i]); 
  1147.     c2 = tolower (s2[i]); 
  1148.     
  1149.     if (c1 != c2) 
  1150.     {
  1151.       return (1); 
  1152.     }
  1153.   }
  1154.   
  1155.   return (0); 
  1156. }
  1157.  
  1158. int strncasecmp (s1, s2, n) 
  1159. char *s1, *s2; 
  1160. int n; 
  1161. {
  1162.   int i; 
  1163.   char c1, c2; 
  1164.   
  1165.   for (i=0; i<n; i++) 
  1166.   {
  1167.     c1 = tolower (s1[i]); 
  1168.     c2 = tolower (s2[i]); 
  1169.     
  1170.     if (c1 != c2) 
  1171.     {
  1172.       return (1); 
  1173.     }
  1174.   }
  1175.   
  1176.   return (0); 
  1177. }
  1178. #endif /* AMIGA */
  1179.  
  1180. void DoLoad ()
  1181. /* 
  1182.  *  Sparky has typed a mission to load 
  1183.  */ 
  1184. {
  1185.   ReadMission (text.buf); 
  1186. }
  1187.